<script setup lang="ts">
import { ref, reactive, unref, defineAsyncComponent, computed, watch } from 'vue'
import {
  ArrowLeft,
  Close,
  ArrowDown,
  Stamp,
  Tickets,
  Timer,
  Avatar,
  BottomLeft,
  EditPen,
  Refresh,
  DArrowLeft,
  DArrowRight
} from '@element-plus/icons-vue'
import { useWfApi } from '@/api/wf'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getNotEmpty } from '@/utils/custom'
import mittBus from '@/utils/mitt'
import type { Fn } from '@vueuse/core'
import type {
  DicType,
  BusinessUIFormType,
  IsWorkFlowDesign,
  RuningDetail,
  WorkflowDesignRow
} from '@/types/custom'
import { Local } from '@/utils/storage'
import { storeToRefs } from 'pinia'
import { useAppState } from '@/stores/appState'

import TemplateForm from '@/views/components/form/TemplateForm.vue'
import AppDetailsChange from '@/components/custom/AppDetailsChange.vue'
import { themeConfig } from '@/storage'

const Workflow = defineAsyncComponent(() => import('@/views/system/flow/workflow/workflow.vue'))

interface Props {
  title: string
  onRuingNext: (option: { callback: Fn; params: object }) => {}
  onUserNext: (callback: Fn) => {}
}

withDefaults(defineProps<Props>(), {
  title: '表单'
})

const emit = defineEmits(['fetch'])

const { mobile } = storeToRefs(useAppState())

const { GetWorkFlowDesignInfo, WorkFlowRuingApproval, WorkFlowRuingDelegate, WorkFlowRuingDel } =
  useWfApi()

// 右边消失
const isAway = ref(Local.get('app_details_away') || false)
const isSave = ref(false)
const formRef = ref()
const wfStatusRef = ref()
const wf_run_id = ref('')
const instanceId = ref('')
const loading = ref(false)
const dialogVisible = ref(false)
const activities = ref<RuningDetail[]>([])
const activeName = ref('form')
const can_edit_items = ref<string[]>([])
const design = ref<WorkflowDesignRow>({ id: '', name: '', nodes: [], edges: [] })
const status = ref(0)
const statusString = ref('')
const detail = ref('')
// 表单字典
const dicTable = ref<DicType[]>([])
// 表单
const uiForm = ref<BusinessUIFormType>({
  id: '',
  api: '',
  method: '',
  type_name: '',
  default_value: '',
  default_value_parse: {},
  items: []
})
// 审批权限
const wfRuning = ref<IsWorkFlowDesign>({
  can_approval: false,
  can_submit: false,
  can_un_approval: false,
  can_un_submit: false,
  can_set_status: false
})

interface RuleForm {
  approvalType: number
  remark: string
  approvalUsersId: string[]
  sendMsg: boolean
  sendSms: boolean
  multApp: boolean
  runingId: string
}

// 表单
const ruleForm = reactive<RuleForm>({
  approvalType: 0,
  remark: '',
  approvalUsersId: [],
  sendMsg: false,
  sendSms: false,
  multApp: false,
  runingId: ''
})

// 审批名称
const approvalTypeNames: TypedAny<string> = {
  0: '审批',
  1: '回退',
  2: '回退到开始',
  3: '不同意',
  99: '委派',
  98: '撤回提交'
}

/**
 * 有一个true就显示按钮
 */
const isWfRuning = computed(() => {
  const values = Object.values(wfRuning.value)
  return values.some((s) => s)
})

/**
 * 审批线
 */
const onIsAway = () => {
  isAway.value = !isAway.value
  Local.set('app_details_away', isAway.value)
}

/**
 * 表格和弹窗都刷新
 */
const onRefreshAll = () => {
  onFetch()
  emit('fetch')
}

/**
 * 关闭弹窗刷新表格刷新
 */
const onCloseRefreshTable = () => {
  emit('fetch')
  dialogVisible.value = false
}

const openStatusChange = () => {
  wfStatusRef.value?.open(wf_run_id.value)
}

/**
 * 流程详情
 */
const onFetch = async () => {
  loading.value = true
  try {
    const { data } = await GetWorkFlowDesignInfo(wf_run_id.value)

    const running = data.runing
    const dic_table = data.dic_table || []
    wfRuning.value = data.wfRuning
    instanceId.value = running.runing.instanceId
    can_edit_items.value = data.can_edit_items || []
    status.value = running.runing.status
    statusString.value = running.runing.statusString
    detail.value = running.runing.remark || ''
    const list: any[] = []
    if (data.runing.node) {
      running.details.push({
        id: '',
        nodeId: data.runing.runing.nodeId,
        nodeLabel: `待 ${data.runing.node.label}`,
        nodeName: `待 ${data.runing.node.label}`,
        approvalUser: data.runing.runing.approvalUsers,
        approvalTypeString: data.runing.runing.statusString,
        nodeType: data.runing.node.nodeType,
        modifiedOnString: ''
      })
    }
    running.details.forEach((v) => {
      // const node = running.design.nodes.find((f) => f.id === v.nodeId)
      // v.label = v.label ? v.label : node?.label || ''
      if (v.nodeId === 'start') {
        v.props = {
          type: 'success',
          hollow: true
        }
      } else if (v.nodeId === 'end') {
        v.props = {
          type: 'danger',
          hollow: false
        }
      } else if (!v.id) {
        v.props = {
          type: 'primary',
          hollow: false
        }
      } else {
        const approvalType: TypedAny = {
          '2': 'warning',
          '3': 'danger'
        }
        v.props = {
          type: getNotEmpty(approvalType, [String(v.approvalType)], 'primary'),
          hollow: false
        }
      }
      list.push(v)
    })

    if (running.design) {
      const nodes = running.design.nodes || []
      const edges = running.design.edges || []

      const start = running.design.nodes.find((f) => f.id === 'start')
      if (start) {
        const starts = [start]
        const results: WorkflowDesignNode[][] = [starts]
        nextNodes(nodes, edges, starts, results)
        let end = false
        results.forEach((nodes) => {
          nodes.forEach((node) => {
            if (!end) {
              node.disabled = !list.some((s) => s.nodeId === node.id)
              if (node.disabled && node.nodeId === 'end') {
                end = true
              }
            }
          })
        })
        // stamps.value = results
      }
      design.value = running.design
      activities.value = list
      isSave.value = !!data.can_edit_items.length
    }
    if (data.ui_form) uiForm.value = data.ui_form
    dicTable.value = dic_table

    if (formRef.value) formRef.value?.onFetch()

    // loading.value = false

  } catch (e) {
    loading.value = false
  }
}

const onFormReady = async () => {
  // 延迟一秒
  await new Promise((resolve) => setTimeout(resolve, 1000))
  // 结束加载
  loading.value = false
}

/**
 * 整个流程
 * @param nodes
 * @param edges
 * @param starts
 * @param results
 */
const nextNodes = (
  nodes: WorkflowDesignNode[],
  edges: WorkflowDesignEdge[],
  starts: WorkflowDesignNode[],
  results: any[]
) => {
  const items: WorkflowDesignNode[] = []
  starts.forEach((n) => {
    const ls = getNodes(nodes, edges, n)
    items.push(...ls)
  })
  if (items.length) {
    results.push(items)
    nextNodes(
      nodes,
      edges,
      items.filter((node) => {
        const lines = edges.filter((f) => f.sourceId === node.id)
        return !items.some((i) => lines.some((s) => s.targetId === i.id))
      }),
      results
    )
  }
  return results
}

/**
 * 获取节点
 * @param nodes
 * @param edges
 * @param node
 */
const getNodes = (
  nodes: WorkflowDesignNode[],
  edges: WorkflowDesignEdge[],
  node: WorkflowDesignNode
) => {
  const lines = edges.filter((f) => f.sourceId === node.id)
  const results: WorkflowDesignNode[] = []
  lines.forEach((line) => {
    const dots = nodes.filter((f) => f.id === line.targetId)
    results.push(...dots)
  })
  return results
}

/**
 * 打开
 */
const open = (row: TypedAny) => {
  dialogVisible.value = true
  wf_run_id.value = getNotEmpty(row, ['wf_runingid', 'objectId'])
  ruleForm.runingId = wf_run_id.value
  ruleForm.remark = ''
  if (wf_run_id.value) onFetch()
}

/**
 * 打开选择用户
 */
const onOpenSelectUser = (): Promise<string | undefined> => {
  return new Promise((callback) => {
    mittBus.emit('onOpenSelectUser', { callback })
  })
}

/**
 * 获取下一步是否需要选择用户
 */
const onOpenRuingNext = (params?: object): Promise<string | undefined> => {
  return new Promise((callback) => {
    mittBus.emit('onOpenRuingNext', { params, callback })
  })
}

/**
 * 弹窗回调
 */
interface MessageBoxInstance {
  done: Fn
  instance: {
    confirmButtonLoading: boolean
    confirmButtonText: string
  }
}

/**
 * 填写审批意见
 */
const openMessageBox = (text: string): Promise<MessageBoxInstance> => {
  return new Promise((resolve) => {
    if (ruleForm.remark) {
      resolve({
        done: () => {},
        instance: { confirmButtonLoading: false, confirmButtonText: text }
      })
    } else {
      ElMessageBox.prompt(`请确认${text}意见`, `${text}意见`, {
        showCancelButton: true,
        confirmButtonText: `确认${text}`,
        cancelButtonText: '取消',
        type: 'warning',
        inputErrorMessage: ``,
        autofocus: false,
        inputValue: ruleForm.approvalType === 0 ? 'OK' : '',
        inputValidator: (value) => {
          return (value || '').trim() ? true : `请输入 ${text} 意见`
        },
        beforeClose: (action, instance, done) => {
          if (action === 'confirm') {
            instance.confirmButtonLoading = true
            instance.confirmButtonText = `${text}中...`
            ruleForm.remark = instance.inputValue
            resolve({ instance, done })
          } else {
            done()
          }
        }
      })
    }
  })
}

/**
 * 提交
 */
const submitForm = async (approvalType: 0 | 1 | 2 | 3 | 98 | 99) => {
  ruleForm.approvalType = approvalType
  if (approvalType === 98) {
    return onCanUnSubmit()
  } else if (approvalType === 99) {
    const userId = await onOpenSelectUser()
    if (userId === 'close') return
    else ruleForm.approvalUsersId = userId ? [userId] : []
  } else if ([0, 99].includes(approvalType)) {
    const userId = await onOpenRuingNext({
      instanceName: design.value.instanceName,
      instanceId: instanceId.value,
      flag: design.value.flag
    })
    if (userId === 'close') return
    else ruleForm.approvalUsersId = userId ? [userId] : []
  }

  // 呼出意见填写
  const text = approvalTypeNames[ruleForm.approvalType]
  const { done, instance } = await openMessageBox(text)
  try {
    if (approvalType === 99) {
      await onDelegate()
    } else {
      await onSubmit()
    }
    onFetch()
    ElMessage.success(`${text} 成功`)
  } catch (e) {
    console.log('审批失败')
  }
  instance.confirmButtonLoading = false
  instance.confirmButtonText = text
  done()
}

/**
 * 委派
 */
const onDelegate = async () => {
  return WorkFlowRuingDelegate({
    runingId: wf_run_id.value,
    approvalUserId: ruleForm.approvalUsersId.length ? ruleForm.approvalUsersId[0] : '',
    remark: ruleForm.remark,
    sendMsg: false,
    sendSms: false
  }).then(() => {
    dialogVisible.value = false
    emit('fetch')
  })
}

/**
 * 提交
 */
const onSubmit = async () => {
  return WorkFlowRuingApproval(ruleForm).then((res) => {
    dialogVisible.value = false
    emit('fetch')
    mittBus.emit('onUpdateMsgDot')
    return res
  })
}

/**
 * 撤回工作流
 */
const onCanUnSubmit = () => {
  ElMessageBox.confirm(`确认要撤回吗？`, '提示框', {
    confirmButtonText: '确认撤回',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      WorkFlowRuingDel(unref(wf_run_id)).then(() => {
        ElMessage.success('撤回成功')
        dialogVisible.value = false
        mittBus.emit('onUpdateMsgDot')
        emit('fetch')
      })
    })
    .catch(() => {})
}

/**
 * 保存
 */
const onSave = () => {
  ElMessageBox.confirm(`确认要保存修改吗？`, '提示框', {
    confirmButtonText: '确认保存',
    cancelButtonText: '取消',
    type: 'warning'
  })
    .then(() => {
      loading.value = true
      formRef.value
        .submitForm()
        .then(({ data }: any) => {
          if (data && data.forms && data.forms.length) {
            // 把数据广播给表单
            mittBus.emit('onUpdateParent', data)
          }
          ElMessage.success('保存成功')
        })
        .finally(() => (loading.value = false))
    })
    .catch(() => {})
}

watch(dialogVisible, (visible) => {
  if (!visible) {
    uiForm.value = {
      id: '',
      api: '',
      method: '',
      type_name: '',
      default_value: '',
      default_value_parse: {},
      items: []
    }
    instanceId.value = ''
  }
})

defineExpose({ open })
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    :title="detail || title"
    width="90%"
    top="5vh"
    append-to-body
    class="custom-dialog"
    destroy-on-close
  >
    <template #header>
      <div class="flex align-center flex-warp pr10" v-if="isWfRuning">
        <el-button class="ml5 mb5" :icon="Close" @click="dialogVisible = false">关闭</el-button>
        <el-button @click="onFetch" class="ml5 mb5" :icon="Refresh" :loading="loading"
        >刷新
        </el-button>
        <el-button
          type="danger"
          v-if="wfRuning.can_set_status"
          class="mb5 ml5"
          @click="openStatusChange"
        >
          修改流程状态
        </el-button>
        <el-button
          v-if="isSave"
          :icon="EditPen"
          type="primary"
          class="ml5 mb5"
          @click="onSave"
          :loading="loading"
        >保存
        </el-button>
      </div>
      <div v-else class="flex align-center flex-warp pr10">
        <span>流程状态：</span>
        <el-tag>{{ statusString }}</el-tag>
        <el-button @click="onFetch" class="ml5" :icon="Refresh" :loading="loading">刷新</el-button>
        <el-button
          v-if="isSave"
          :icon="EditPen"
          type="primary"
          class="ml5"
          @click="onSave"
          :loading="loading"
        >
          保存
        </el-button>
      </div>
    </template>
    <el-row
      :gutter="5"
      style="min-height: 76vh"
      v-loading="loading"
      element-loading-text="奋力加载中..."
      :element-loading-background="themeConfig.isIsDark ? '#000000':'#ffffff'"
      class="app-detail-loading"
    >
      <el-col
        :xs="24"
        :sm="isAway ? 24 : 16"
        :md="isAway ? 24 : 18"
        :lg="isAway ? 24 : 19"
        :xl="isAway ? 24 : 20"
      >
        <div class="font18 font-bold flex-grow flex align-center justify-between">
          <span>{{ detail || title }}</span>
          <el-button
            v-if="!mobile"
            class="home-left-btn animate__animated animate__fadeInRight ml-auto"
            :icon="isAway ? DArrowLeft : DArrowRight"
            @click="onIsAway"
          >
            时间线
          </el-button>
        </div>
        <el-tabs v-model="activeName" class="flex-grow">
          <el-tab-pane label="审批详情" name="form">
            <template #label>
              <div class="flex align-center">
                <el-icon>
                  <Tickets />
                </el-icon>
                <span class="ml5">审批详情</span>
              </div>
            </template>
            <!--            <CustomForm ref="formRef" :ui-form="uiForm" :dic-table="dicTable" :can_edit_items="can_edit_items"-->
            <!--                        class="flex-grow" :details="!can_edit_items.length"/>-->
            <TemplateForm
              v-if="instanceId"
              ref="formRef"
              :is-form="!!can_edit_items.length"
              v-model="instanceId"
              :ui-form="uiForm"
              :dic-table="dicTable"
              :can_edit_items="can_edit_items"
              :ready="onFormReady"
            />
          </el-tab-pane>
          <el-tab-pane label="审批工作流" name="stamp" v-if="!mobile">
            <template #label>
              <div class="flex align-center">
                <el-icon>
                  <Stamp />
                </el-icon>
                <span class="ml5">审批工作流</span>
              </div>
            </template>
            <Workflow
              v-if="activeName === 'stamp' && design.id"
              :design="design"
              hide-tool
              style="padding: 0 !important; height: 76vh; position: relative"
            />
          </el-tab-pane>
        </el-tabs>
      </el-col>
      <el-col v-if="!isAway" :xs="24" :sm="8" :md="6" :lg="5" :xl="4">
        <el-card shadow="hover" class="flex-shrink">
          <template #header>
            <div class="flex align-center color-primary">
              <el-icon>
                <Timer />
              </el-icon>
              <span class="ml5">审批时间线</span>
            </div>
          </template>
          <el-timeline v-if="activities.length">
            <el-timeline-item
              v-for="(activity, index) in activities"
              :key="index"
              v-bind="activity.props || {}"
              :timestamp="activity.modifiedOnString"
            >
              <div class="font14 mb5">{{ activity.nodeName }}</div>

              <div class="color-info font12 mb5" v-if="activity.submitUser">
                提交人：{{ activity.submitUser }}
              </div>
              <div class="color-info font12 mb5" v-if="activity.approvalUser">
                <span
                  >{{
                    { '0': '提交人', '1': '结束', '2': '审批人', '3': '抄送至' }[
                      String(activity.nodeType)
                    ]
                  }}：{{ activity.approvalUser }}</span
                >
                <span v-if="activity.approvalTypeString && activity.nodeType === 2"
                  >（{{ activity.approvalTypeString }}）</span
                >
              </div>
              <div v-if="activity.remark" class="font12">
                <span class="color-info">意见：</span>
                <span class="color-warning">{{ activity.remark }}</span>
              </div>
            </el-timeline-item>
          </el-timeline>
        </el-card>
      </el-col>
    </el-row>
    <div style="width: 100%;height: 70px"></div>
    <AppDetailsChange ref="wfStatusRef" @fetch="onRefreshAll" @close="onCloseRefreshTable" />
    <template #footer>
      <div class="custom-dialog-footer">
        <el-button class="ml5 mb5" :icon="Close" @click="dialogVisible = false">关闭</el-button>
        <el-input
          v-if="wfRuning.can_approval"
          style="width: 290px"
          v-model="ruleForm.remark"
          placeholder="请输入意见"
          type="text"
          class="ml5 mb5"
        />
        <el-button
          v-if="wfRuning.can_approval"
          type="primary"
          @click="submitForm(0)"
          :loading="loading"
          :icon="Stamp"
          class="mb5 ml5 px20"
        >
          同意审批
        </el-button>
        <el-dropdown @command="submitForm" v-if="wfRuning.can_un_submit || wfRuning.can_approval">
          <el-button :icon="ArrowDown" :loading="loading" class="mb5 ml5">更多操作</el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item :command="98" v-if="wfRuning.can_un_submit">
                <el-button type="danger" style="width: 100%" :icon="BottomLeft">撤回提交</el-button>
              </el-dropdown-item>
              <el-dropdown-item :command="99" v-if="wfRuning.can_approval">
                <el-button type="success" style="width: 100%" :icon="Avatar">委派</el-button>
              </el-dropdown-item>
              <!--                <el-dropdown-item :command="0">-->
              <!--                  <el-button type="primary" style="width: 100%" :icon="Stamp">同意审批</el-button>-->
              <!--                </el-dropdown-item>-->
              <el-dropdown-item :command="1" v-if="wfRuning.can_approval">
                <el-button type="warning" style="width: 100%" :icon="BottomLeft"
                >回退上一步
                </el-button>
              </el-dropdown-item>
              <el-dropdown-item :command="2" v-if="wfRuning.can_approval">
                <el-button type="warning" style="width: 100%" :icon="ArrowLeft"
                >回退到开始
                </el-button>
              </el-dropdown-item>
              <el-dropdown-item :command="3" v-if="wfRuning.can_approval">
                <el-button type="danger" style="width: 100%" :icon="Close">不同意</el-button>
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </template>
  </el-dialog>
</template>
<style>
.app-detail-loading .el-loading-spinner {
  top: 200px !important;
  margin-top: 0 !important;
}
</style>
